
/*

Design Pattern Automation Toolkit.
Application to create applications with emphasis on Design patterns.
And support for round trip engineering.
Copyright (C) 2004 Vineeth Neelakant. nvineeth@gmail.com

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
using System;
using dpatoolkit.UILayer;
using System.Drawing;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using DesignPatternDefinitions;
using System.Drawing.Drawing2D;
using System.Drawing.Design;
using BusinessLayer;

namespace dpatoolkit.UILayer
{
	/// <summary>
	/// Summary description for PluginEditorForm.
	/// </summary>
	public class PluginEditorForm : WeifenLuo.WinFormsUI.Docking.DockContent,/* System.Windows.Forms.Form */IMdiChild , IUIProjectUnit
    {
        private IContainer components;

		protected ClassDiagram uicomponent;
		protected IDesignPatternSubject subject;
		public static string pluginTag="Plugin";
        private TreeView treeView;
		private TreeNode pluginNode;
        private string pluginFilePath = string.Empty;
        private MenuItem closeMenuItem;
        private MenuItem SavePlugin;
        private ContextMenu TreeViewContextMenu;
        private TabControl tabControl;
        private TabPage tabPageClsDia;
        private TabPage tabPageDetails;
        private ComboBox catComboBox;
        private TextBox dpnameTextBox;
        private RichTextBox richTextBoxDetails;
        private Label label1;
        private Label label3;
        private Label label2;
        private IUIProjectUnit project;
        private string designPatternName = string.Empty;



		public PluginEditorForm(string pname , IDesignPatternSubject sub)
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			subject=sub;
			this.Text=pname;
           			
            //init the tree View
			this.treeView=DPAppData.MDIManager.ProjectTreeView;
			this.UpdateUI();
			this.Project = this;
            this.TabText = this.dpnameTextBox.Text;
            this.WindowState = FormWindowState.Maximized;
            DPAppData.MDIManager.AddDocument(this);

            
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		protected void InitializeComponent() 
		{
            this.closeMenuItem = new System.Windows.Forms.MenuItem();
            this.SavePlugin = new System.Windows.Forms.MenuItem();
            this.TreeViewContextMenu = new System.Windows.Forms.ContextMenu();
            this.tabControl = new System.Windows.Forms.TabControl();
            this.tabPageClsDia = new System.Windows.Forms.TabPage();
            this.tabPageDetails = new System.Windows.Forms.TabPage();
            this.catComboBox = new System.Windows.Forms.ComboBox();
            this.label3 = new System.Windows.Forms.Label();
            this.dpnameTextBox = new System.Windows.Forms.TextBox();
            this.label2 = new System.Windows.Forms.Label();
            this.label1 = new System.Windows.Forms.Label();
            this.richTextBoxDetails = new System.Windows.Forms.RichTextBox();
            this.tabControl.SuspendLayout();
            this.tabPageDetails.SuspendLayout();
            this.SuspendLayout();
            // 
            // closeMenuItem
            // 
            this.closeMenuItem.Index = 0;
            this.closeMenuItem.Text = "Close";
            this.closeMenuItem.Click += new System.EventHandler(this.closeMenuItem_Click);
            // 
            // SavePlugin
            // 
            this.SavePlugin.Index = 1;
            this.SavePlugin.Text = "Save";
            this.SavePlugin.Click += new System.EventHandler(this.SavePlugin_Click);
            // 
            // TreeViewContextMenu
            // 
            this.TreeViewContextMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.closeMenuItem,
            this.SavePlugin});
            // 
            // tabControl
            // 
            this.tabControl.Appearance = System.Windows.Forms.TabAppearance.FlatButtons;
            this.tabControl.Controls.Add(this.tabPageClsDia);
            this.tabControl.Controls.Add(this.tabPageDetails);
            this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill;
            this.tabControl.HotTrack = true;
            this.tabControl.Location = new System.Drawing.Point(0, 0);
            this.tabControl.Multiline = true;
            this.tabControl.Name = "tabControl";
            this.tabControl.SelectedIndex = 0;
            this.tabControl.ShowToolTips = true;
            this.tabControl.Size = new System.Drawing.Size(696, 398);
            this.tabControl.TabIndex = 4;
            // 
            // tabPageClsDia
            // 
            this.tabPageClsDia.AutoScroll = true;
            this.tabPageClsDia.Location = new System.Drawing.Point(4, 25);
            this.tabPageClsDia.Name = "tabPageClsDia";
            this.tabPageClsDia.Padding = new System.Windows.Forms.Padding(3);
            this.tabPageClsDia.Size = new System.Drawing.Size(688, 369);
            this.tabPageClsDia.TabIndex = 0;
            this.tabPageClsDia.Text = "Class Diagram";
            this.tabPageClsDia.ToolTipText = "The Class Diagram of the Design Pattern";
            this.tabPageClsDia.UseVisualStyleBackColor = true;
            // 
            // tabPageDetails
            // 
            this.tabPageDetails.Controls.Add(this.catComboBox);
            this.tabPageDetails.Controls.Add(this.label3);
            this.tabPageDetails.Controls.Add(this.dpnameTextBox);
            this.tabPageDetails.Controls.Add(this.label2);
            this.tabPageDetails.Controls.Add(this.label1);
            this.tabPageDetails.Controls.Add(this.richTextBoxDetails);
            this.tabPageDetails.Location = new System.Drawing.Point(4, 25);
            this.tabPageDetails.Name = "tabPageDetails";
            this.tabPageDetails.Padding = new System.Windows.Forms.Padding(3);
            this.tabPageDetails.Size = new System.Drawing.Size(688, 369);
            this.tabPageDetails.TabIndex = 1;
            this.tabPageDetails.Text = "Design pattern Details";
            this.tabPageDetails.ToolTipText = "Design Pattern Description";
            this.tabPageDetails.UseVisualStyleBackColor = true;
            // 
            // catComboBox
            // 
            this.catComboBox.Items.AddRange(new object[] {
            "Creational",
            "Structural",
            "Behavioral"});
            this.catComboBox.Location = new System.Drawing.Point(427, 17);
            this.catComboBox.Name = "catComboBox";
            this.catComboBox.Size = new System.Drawing.Size(253, 21);
            this.catComboBox.TabIndex = 0;
            // 
            // label3
            // 
            this.label3.AutoSize = true;
            this.label3.Location = new System.Drawing.Point(372, 20);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(49, 13);
            this.label3.TabIndex = 8;
            this.label3.Text = "Category";
            // 
            // dpnameTextBox
            // 
            this.dpnameTextBox.Location = new System.Drawing.Point(122, 17);
            this.dpnameTextBox.Name = "dpnameTextBox";
            this.dpnameTextBox.Size = new System.Drawing.Size(229, 20);
            this.dpnameTextBox.TabIndex = 0;
            this.dpnameTextBox.TextChanged += new System.EventHandler(this.dpnameTextBox_TextChanged);
            // 
            // label2
            // 
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(6, 20);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(108, 13);
            this.label2.TabIndex = 7;
            this.label2.Text = "Design Pattern Name";
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(8, 46);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(133, 13);
            this.label1.TabIndex = 6;
            this.label1.Text = "Design Pattern Description";
            // 
            // richTextBoxDetails
            // 
            this.richTextBoxDetails.AcceptsTab = true;
            this.richTextBoxDetails.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.richTextBoxDetails.Location = new System.Drawing.Point(10, 65);
            this.richTextBoxDetails.Name = "richTextBoxDetails";
            this.richTextBoxDetails.Size = new System.Drawing.Size(670, 287);
            this.richTextBoxDetails.TabIndex = 5;
            this.richTextBoxDetails.Text = "";
            // 
            // PluginEditorForm
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.AutoScroll = true;
            this.ClientSize = new System.Drawing.Size(696, 398);
            this.CloseButton = false;
            this.Controls.Add(this.tabControl);
            this.HideOnClose = true;
            this.Name = "PluginEditorForm";
            this.TabText = "Design pattern editor";
            this.Text = "Design pattern editor";
            this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
            this.tabControl.ResumeLayout(false);
            this.tabPageDetails.ResumeLayout(false);
            this.tabPageDetails.PerformLayout();
            this.ResumeLayout(false);

		}
		#endregion

        protected void CreatePluginTreeNode(string pname)
		{
			this.pluginNode=new TreeNode(pname,2,2);
			this.treeView.Nodes.Add(this.pluginNode);
			TreeNode classDiaNode = new TreeNode("Class Diagram",3,3);
			TreeNode pluginInfoNode = new TreeNode("Plugin Details",3,3);
			classDiaNode.Tag = this;
			pluginInfoNode.Tag = this;
			this.pluginNode.Nodes.AddRange( new TreeNode[]{
									      classDiaNode,
									      pluginInfoNode
								      }
				);
			this.pluginNode.Tag=this;
		}

		#region IMdiChild Members

        public void Print(Graphics g)
        {
            this.uicomponent.Print(g);
        }

		public void Print()
		{
			this.uicomponent.Print();
		}

		public	new void Close()
		{
            DPAppData.MDIManager.RemoveDocument(this);
            this.treeView.Nodes.Remove(this.pluginNode);
		}

		public void ClearAll()
		{
			this.uicomponent.ClearAll();
		}

		public void SaveAsImage(string path)
		{
			this.uicomponent.SaveAsImage(path);
		}

		public void MergePattern(string pathToPatternFile)
		{
			//During the merge of a Design pattern, the 
			//UIComponent design is completely cleared 
			//and redrawn. This is more clear and efficient.
			this.ClearAll();
			//tell the Subject to merge a pattern and the UIComponent to update after the merge.
            // TODO : *** This ugly looking piece of code will be fixed when the complete APIs are rewritten! ***
            IProject proj = this.subject.GetProject();
            IProjectComponent desPatComp = proj.Components[0] as IProjectComponent;
            this.subject.Merge(desPatComp.ComponentName, pathToPatternFile);
			
		}

        public void OpenComponent(string fname)
        {
            //now the project has been read :)
            this.subject.ReadProject(fname);
            IDesignPattern pattern = this.subject as IDesignPattern;

            if (!pattern.IsPattern())
            {
                ErrorMessage.Show("This is not a Design Pattern", "Error");
                this.Close();
                return;
            }
            
            this.uicomponent = new ClassDiagram(PluginEditorForm.pluginTag, this.subject, this.tabPageClsDia);
            this.tabPageClsDia.Controls.Add(uicomponent);
            this.uicomponent.AdjustLocation();
            this.subject.UpdateComponents();

            // now update the tabs;
            IDictionary<string, string> dpDetails = pattern.DesignPatternDetails;
            foreach (KeyValuePair<string, string> kvp in dpDetails)
            {
                if (kvp.Key == PlugInDetailsForm.DesignPatternName)
                {
                    this.dpnameTextBox.Text = ConvertRTFtoPlainText(kvp.Value);
                }
                else if (kvp.Key == PlugInDetailsForm.DesignPatternCategory)
                {
                    this.catComboBox.Text = ConvertRTFtoPlainText(kvp.Value);
                }
                else if (kvp.Key == PlugInDetailsForm.DesignPatternDetails)
                {
                    try
                    {
                        this.richTextBoxDetails.Rtf = kvp.Value;
                    }
                    catch
                    {
                        this.richTextBoxDetails.Text = ConvertRTFtoPlainText(kvp.Value);
                    }
                }
                else
                {
                    // Probably a Design Pattern Detail From Older Versions.
                    this.richTextBoxDetails.AppendText("\n" + ConvertRTFtoPlainText(kvp.Key) + "\n");
                    this.richTextBoxDetails.AppendText(ConvertRTFtoPlainText(kvp.Value) + "\n");
                }
            }
            this.pluginFilePath = fname;
        }

        public string Title
        {
            set { this.TabText = (string)value; }
            get { return this.TabText; }
        }

        public IUIProjectUnit Project
        {
            get
            {
                return this.project;
            }
            set
            {
                this.project = value;
            }
        }
		#endregion
		
		public static string ConvertRTFtoPlainText(string rtf)
		{
			//Routine to convert from rtf to plain text
			string plainTxt;
			RichTextBox rtb = new RichTextBox();
			try
			{
				rtb.Rtf = rtf;
			}
			catch
			{
				//If an exception is caught then the provided arg is not in rtf format, so return the arg as it is!
				rtb.Text= rtf;
			}
			finally
			{
				plainTxt= rtb.Text;
				plainTxt.Trim();
			}
			return plainTxt;
		}

		#region event handlers for link label,buttons, etc
			
		private void dpnameTextBox_TextChanged(object sender, System.EventArgs e)
		{
            this.designPatternName = this.dpnameTextBox.Text;

            if (this.designPatternName != string.Empty)
			{
                this.pluginNode.Text = this.designPatternName;
                this.TabText = this.designPatternName;
			}
			else
			{
				this.pluginNode.Text="NoName Design Pattern";
				this.TabText= "NoName Design Pattern";
			}
		}
		#endregion

		protected bool GeneratePlugin()
		{
			//STEP:1 Check for null entries
            if (this.dpnameTextBox.Text == string.Empty)
            {
                //ErrorMessage.Show("Please Enter the Design Pattern Name","Error");
                //return false;
                this.dpnameTextBox.Text = "[NoName Design Pattern]";
            }

			if ( this.uicomponent.UIElementsCount ==0)
			{
				ErrorMessage.Show("The structure (Class Diagram) of the plugin is empty.\n You Forgot to construct the class diagram! ","Error");
				//return false;
			}

			//STEP:2 Write the details of each tab
            // Write the pattern name.
            IDesignPattern pattern = this.subject as IDesignPattern;

            pattern.ClearDetails();

            pattern[PlugInDetailsForm.DesignPatternName] = this.dpnameTextBox.Text;
            pattern[PlugInDetailsForm.DesignPatternCategory] = this.catComboBox.Text;
            pattern[PlugInDetailsForm.DesignPatternDetails] = this.richTextBoxDetails.Rtf;

			//STEP:3 Write the UIDetails 
			this.uicomponent.WriteUIDetails();

			//STEP:4 Save the subject as plugin..
			if(this.pluginFilePath==string.Empty)
			{
				SaveFileDialog saveDialog = new SaveFileDialog();
                saveDialog.Title = "Save Design Pattern " + this.designPatternName;
                saveDialog.Filter = "xml files (*.plugin.xml)|*.plugin.xml";
                saveDialog.FilterIndex = 1; // select xml
                saveDialog.OverwritePrompt = true;
                saveDialog.AddExtension = true;
                saveDialog.DefaultExt = "*.plugin.xml";

                if (saveDialog.ShowDialog() == DialogResult.Cancel)
					return true;//yes true because the user is aware!
                this.pluginFilePath = saveDialog.FileName;
			}
            if( this.subject.WriteProject(this.pluginFilePath))
                DPAppData.MDIManager.ShowStatusMessage("Design Pattern : " + this.designPatternName + " saved", 5000);
			else
                DPAppData.MDIManager.ShowStatusMessage("Design Pattern : " + this.designPatternName + "could not be saved");
			return true;
		}
			
		#region IUIProjectUnit Members

		public event ProjectClosing ProjectClosing;

        public bool New(ProjectComponentType compType)
		{
            IProjectComponent comp = new InfoClasses.ProjectComponentInfo
            {
                ComponentName = pluginTag,
                ComponentAuthor = "Plugin",
                ComponentSummary = ""
            };
            this.subject.CreateNewComponent(comp);
            this.uicomponent = new ClassDiagram(PluginEditorForm.pluginTag, this.subject, this.tabPageClsDia);
            this.tabPageClsDia.Controls.Add(uicomponent);
            this.uicomponent.AdjustLocation();
            this.dpnameTextBox.Text = "New Design Pattern";
            return true;
		}

		public bool Command(MdiCommand command)
		{
			if (command == MdiCommand.GenerateSnapshot )
			{
				OpenFileDialog dialog = new OpenFileDialog();
				if ( dialog.ShowDialog()== DialogResult.Cancel)
					return false;
				this.SaveAsImage(dialog.FileName);
			}
			else if(command == MdiCommand.AddNewComponent )
			{
				InfoMessage.Show("Cannot Add a component to a plugin.","Info");	
			}
			return false;
		}

		public bool Open(string filename)
		{
            this.OpenComponent(filename);
			return true;
		}

		public bool Open(IDesignPatternSubject subject)
		{
            throw new NotImplementedException();
		}

		public bool Save(bool confirm)
		{
            if (confirm)
            {
                DialogResult res = DialogResult.None;
                res = MessageBox.Show(
                    this, "Save Changes to Design Pattern : " + this.designPatternName + "?",
                    "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

                if (res != DialogResult.Yes)
                    return false;
            }
            this.GeneratePlugin();
			return true;
		}

		public bool SaveAs()
		{
			// TODO:  Add PluginEditorForm.SaveAs implementation
			return false;
		}

		public string File()
		{
            return this.pluginFilePath;
		}

		public string ProjectName()
		{
			// TODO:  Add PluginEditorForm.Name implementation
			return null;
		}

		public void UpdateUI()
		{
			/* Update the tree View */
			this.treeView=DPAppData.MDIManager.ProjectTreeView;
			if(this.subject!=null)
			{
				this.CreatePluginTreeNode("Design Pattern");
				
			}
			this.treeView.MouseDown+=new MouseEventHandler(treeViewMouseDown);
			this.treeView.DoubleClick+=new EventHandler(treeViewDoubleClick);
		}


		#region tree view event handlers
		
		private void treeViewMouseDown(object sender, MouseEventArgs e)
		{
			TreeView tv = sender as TreeView;
			TreeNode clickedNode = tv.GetNodeAt(e.X,e.Y);
			if (clickedNode == null)
				return;
			if (clickedNode.Tag != this)
				return; //doesnot not belong to me..somebody else will handle this.
			
			tv.SelectedNode = clickedNode;

			if(e.Button==MouseButtons.Right)
			{
				
				this.TreeViewContextMenu.Show(tv,new Point(e.X,e.Y));
				
			}
		}

		private void treeViewDoubleClick(object sender, EventArgs e)
		{
			TreeView tv = sender as TreeView;
			TreeNode node = tv.SelectedNode;
			if(node == null)
				return;
			if (node.Tag != this)
				return;
			

			bool docOpen = false;
			bool belongsToMe=false;
			foreach(IMdiChild child in DPAppData.MDIManager.Documents)
			{
				if(child.Project == this)
				{
					DPAppData.MDIManager.CurrentDocument = child;
                    this.Visible = true;
                    this.Show();
				}
			}
			if((belongsToMe && !docOpen) || DPAppData.MDIManager.Documents.Count==0) 
			{
				//then create a new component, because it has been closed by the user.
				
			}
			if(node.Parent != this.pluginNode)
				return;
			if (node.Index == 0)
                this.tabControl.SelectedTab = this.tabPageClsDia;
			else
                this.tabControl.SelectedTab = this.tabPageDetails;
		}
		
		#endregion

		public void Recover()
		{
			this.subject.WriteProject();
		}

		private void closeMenuItem_Click(object sender, System.EventArgs e)
		{
            /* ask the user confirmation */
            this.Save(true);
            /* close and fire the event */
			this.Close();
            ProjectClosing(this);
		}

		private void SavePlugin_Click(object sender, System.EventArgs e)
		{
			this.GeneratePlugin();
		}
		

		public IDesignPatternSubject Subject
		{
			get
			{
				return this.subject;
			}
			set
			{
				// TODO:  Add PluginEditorForm.Subject setter implementation
			}
		}

		public ProjectType ProjectType
		{
			get
			{
				return ProjectType.DesignPatternPlugin;
			}
		}

		#endregion
	}

}

